package com.atguigu.springanalysis.allot;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;

public class AllotSample {
    public static void main(String[] args) throws IOException {
        final byte[] bytes = Files.readAllBytes(Paths.get("E:\\sojson.com.json"));
        ObjectMapper objectMapper = new ObjectMapper();
        List<Sample> sampleList = objectMapper.readValue(bytes, new TypeReference<List<Sample>>() {
        });
        sampleList = produceSample(7,10,1,1,1);
//        sampleList = produceSample(4,3,1,0,0);
//        sampleList = produceSample(6,4,1,1,0);
//        sampleList = produceSample(5,3,1,1,0);
//        sampleList = produceSample(4,2,1,1,0);
//        sampleList = produceSample(3,1,1,1,0);
//        sampleList = produceSample(4,1,1,1,1);
//        sampleList = produceSample(5,2,1,1,1);

        System.out.println(sampleList);
        final Map<String, Long> orgNameWithNo = sampleList.stream().collect(Collectors.groupingBy(Sample::getOrgName, Collectors.counting()));

        Map<String, Long> result2 = new LinkedHashMap<>();
        orgNameWithNo.entrySet().stream()
                .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
                .forEachOrdered(x -> result2.put(x.getKey(), x.getValue()));

        System.out.println(orgNameWithNo);
        System.out.println(result2);

        final Map<String, List<Sample>> groupByOrgList = sampleList.stream().collect(Collectors.groupingBy(Sample::getOrgName));
        System.out.println(groupByOrgList);

        final Map<String, List<String>> groupIdByOrgNameList = sampleList.stream().collect(Collectors.groupingBy(Sample::getOrgName, Collectors.mapping(Sample::getAllotId, Collectors.toList())));
        System.out.println(groupIdByOrgNameList);

        ArrayList<String> orgNameList = Lists.newArrayList(result2.keySet());
        orgNameList.add("test");
        orgNameList.remove("广州");
        List<String> orgNameListCopy = objectMapper.readValue(objectMapper.writeValueAsString(orgNameList), new TypeReference<List<String>>() {
        });
        System.out.println(orgNameList);

//        for (int i = 0; i < orgNameList.size(); i++) {
//
//        }
        int j = 1;
        Map<String,Integer> orgAllotMap = new HashMap<>();
        final int ceilNum = (int)Math.ceil((double) sampleList.size() / (double) orgNameList.size());
        final int floorNum = (int)Math.floor((double) sampleList.size() / (double) orgNameList.size());
        if(ceilNum * (orgNameList.size() - 1) >= result2.get(orgNameList.get(0))){
            for (int i = 0; i < sampleList.size(); i++) {
                int index = (i % orgNameList.size());
                String orgName = orgNameList.get(index);
                Sample currentSample = sampleList.get(i);
                Integer allotNum = orgAllotMap.get(orgName) == null ? 0 :orgAllotMap.get(orgName);


                if(ceilNum == floorNum){
                    while (StringUtils.equals(orgName,currentSample.getOrgName()) || (allotNum == ceilNum)){
                        index = (index + j) % orgNameList.size();
                        orgName = orgNameList.get(index);
                        allotNum = orgAllotMap.get(orgName) == null ? 0 :orgAllotMap.get(orgName);
                    }
                }else {
                    final List<Map.Entry<String, Integer>> collect = orgAllotMap.entrySet().stream().filter(e -> e.getValue() >= floorNum).collect(Collectors.toList());
                    Long maxNum = result2.get(orgNameList.get(0));
                    final int allotCycleNum = orgNameList.size();
//                    if((collect.size() >= allotCycleNum && floorNum * allotCycleNum > maxNum)){
                    if(collect.size() >= orgNameList.size()){
                        while (StringUtils.equals(orgName,currentSample.getOrgName()) || (allotNum == ceilNum)){
                            index = (index + j) % orgNameList.size();
                            orgName = orgNameList.get(index);
                            allotNum = orgAllotMap.get(orgName) == null ? 0 :orgAllotMap.get(orgName);
                        }
                    }else {

                        if(collect.size() == (orgNameList.size()-1) && (collect.size() * floorNum < maxNum)){
                            final String maxNumOrgName = orgNameList.get(0);
                            if(!StringUtils.equals(maxNumOrgName,currentSample.getOrgName())){
                                orgName = maxNumOrgName;
                                allotNum = orgAllotMap.get(orgName) == null ? 0 :orgAllotMap.get(orgName);
                            }else {
                                while (StringUtils.equals(orgName,currentSample.getOrgName()) || (allotNum == ceilNum)){
                                    index = (index + j) % orgNameList.size();
                                    orgName = orgNameList.get(index);
                                    allotNum = orgAllotMap.get(orgName) == null ? 0 :orgAllotMap.get(orgName);
                                }
                            }
                        }else {
                            while (StringUtils.equals(orgName,currentSample.getOrgName()) || (allotNum == floorNum)){
                                index = (index + j) % orgNameList.size();
                                orgName = orgNameList.get(index);
                                allotNum = orgAllotMap.get(orgName) == null ? 0 :orgAllotMap.get(orgName);
                            }
                        }
                    }
                }
                orgAllotMap.put(orgName,allotNum+1);
                currentSample.setAssignOrgName(orgName);
            }
        }else {
            final String maxNumOrgName = orgNameList.get(0);
            orgNameListCopy.remove(maxNumOrgName);
            for (int i = 0; i < sampleList.size(); i++) {
                Sample currentSample = sampleList.get(i);
                if(!StringUtils.equals(maxNumOrgName,currentSample.getOrgName())){
                   currentSample.setAssignOrgName(maxNumOrgName);
                   continue;
                }
                int index = (i % orgNameListCopy.size());
                String orgName = orgNameListCopy.get(index);
                currentSample.setAssignOrgName(orgName);
            }
        }


        System.out.println(sampleList);
//        Map<String, List<String>> collect = sampleList.stream()
//                .collect(Collectors.toMap(e -> e.getAssignOrgName(), e -> e.getOrgName() + "_" + e.getAllotId()))
//                .entrySet().stream()
//                .collect(Collectors.groupingBy(e -> e.getKey(), Collectors.mapping(e -> e.getValue(), Collectors.toList())));
        final Map<String, List<String>> collect = sampleList.stream().collect(Collectors.groupingBy(Sample::getAssignOrgName, Collectors.mapping(e -> e.getOrgName() + "_" + e.getAllotId(), Collectors.toList())));
        System.out.println(collect);
        System.out.println(ceilNum);
        System.out.println(floorNum);

//        System.out.println(produceSample(8,4,2,1,1));

        // 2,1 3,1
        //1/3 1/2 2/3 ,  1/4 1/2 3/4
        // 5,1,1   BC  AAA  AA
        // m,n (m+n)/(n+1) m/(n+1) 1/(n+10.+30
        // +)
    }

    private static List<Sample> produceSample(Integer totalNum,Integer guangzhou,Integer wuhan,Integer xiangyang,Integer ningxia){
        List<Sample> samples = new ArrayList<Sample>();
        totalNum = guangzhou + wuhan + xiangyang + ningxia;
        for (int i = 1; i <= totalNum; i++) {
            Sample sample = new Sample();
            sample.setAllotId(i+"");
            if(i <= guangzhou){
                sample.setOrgName("广州");
            }
            if(guangzhou < i && i <= (guangzhou + wuhan)){
                sample.setOrgName("武汉");
            }
            if(guangzhou + wuhan < i && i <= (guangzhou + wuhan + xiangyang)){
                sample.setOrgName("襄阳");
            }
            if(guangzhou + wuhan + xiangyang < i && i <= (guangzhou + wuhan + xiangyang + ningxia)){
                sample.setOrgName("宁夏");
            }
            samples.add(sample);
        }
        return samples;
    }

    @Data
    public static class Sample{
        private String allotId;
        private String orgName;
        private String assignOrgName;
    }
}
